package utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Properties;

public class PropertiesInvoker {
	Properties properties;
	public PropertiesInvoker(String fileName) throws IOException {
		properties=new Properties();
		properties.load(new FileInputStream(fileName));		
	}
	
	private void loadProperties(Object object,String fieldName) throws IOException,
		FileNotFoundException, IllegalAccessException,
		InvocationTargetException, SecurityException, IllegalArgumentException, NoSuchMethodException, InstantiationException {
	
		Enumeration<Object> keys=properties.keys();
		
		while(keys.hasMoreElements()) {
					
			String key=""+keys.nextElement();
			String v=""+properties.getProperty(key,null);
			String keyNoField=key.substring(key.indexOf(".")+1);						
			
			boolean b=false;
			b=b || invokeMethodInt(object, keyNoField, v);
			b=b || invokeMethodBoolean(object, keyNoField, v);		
			b=b || invokeMethodString(object, keyNoField, v);
			b=b || invokeMethodObject(object, keyNoField, v);
			if (!b) {
				System.out.println("warning: parameter key:"+key+" value:"+v+" ignored (there is no object/method with that name and correct signature).");
			}
		
		}
	}

	private static boolean invokeMethodString(Object object, String key, String v) throws IllegalAccessException, InvocationTargetException {
		Method m;
		try {
			m=object.getClass().getMethod(key, String.class);
		} catch(Exception ex) {
			m=null;
		}
		if (m!=null) {
			String value=""+v;
			m.invoke(object, value);
			System.out.println("setting string:"+key+" value:"+value);
			return true;
		}
		return false;
	}

	private static boolean invokeMethodBoolean(Object object, String key,String v) throws IllegalAccessException, InvocationTargetException {
		Method m;
		m=null;
		try {
			m=object.getClass().getMethod(key, boolean.class);
		} catch(Exception ex) {
			m=null;
		}
		if (m!=null) {
			boolean value=Boolean.parseBoolean(v);
			m.invoke(object, value);
			System.out.println("setting boolean:"+key+" value:"+value);
			return true;
		}
		return false;
		}
		
		private static Method findMethod(Object object,String key,Class parentClass) {
		for(Method m:object.getClass().getMethods()) {
			if (m.getName().equals(key) && m.getParameterTypes().length>0 && parentClass.isAssignableFrom(m.getParameterTypes()[0]) ) {
				return m;
			}
		}
		return null;
	}


	private static boolean invokeMethodObject(Object object, String key, String v) throws IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException {

		Method m=null;
		
		try {			
			m=findMethod(object,key, Object.class);			
		} catch(Exception ex) {
			//no hacemos nada.
		}
		
		if (m!=null) {
			String value=v;
			System.out.println("setting object:"+key+" value:"+value);
			
			if (value.indexOf("new:")>=0) {
				String newText=value.split("new:")[1];
				String[] frags=newText.split("arg:");
				System.out.println(Arrays.toString(frags));
				try {
					Class<?> clazz=Class.forName(frags[0].trim());
					Constructor c=clazz.getConstructor(String.class);
					m.invoke(object, c.newInstance(frags[1]));
				} catch (ClassNotFoundException e) {
					System.err.println("warning: class not found:"+frags[0].trim());
				}
				return false;
			} else {
				Constructor c=m.getParameterTypes()[0].getConstructor(String.class);
				m.invoke(object, c.newInstance(value));
				return true;
			}
		}
		return false;
	}

	private static boolean invokeMethodInt(Object object, String key, String v) throws IllegalAccessException, InvocationTargetException {
	
		Method m=null;
				
		try {
			m=object.getClass().getMethod(key, int.class);
		} catch(Exception ex) {
			//no hacemos nada.
		}
		
		if (m!=null) {
			int value=Integer.parseInt(v);
			m.invoke(object, value);
			System.out.println("setting int:"+key+" value:"+value);
			return true;
		}
		return false;
	}

}
